package com.otp.service.util;

import java.util.List;

public class MathematicalFunctions {

	public static double normalPDF(double x, double mean, double sigma){

		double pi = java.lang.Math.PI;
		double term1 = 1.0/(java.lang.Math.sqrt(2*pi)*sigma);
		double term2 = java.lang.Math.exp(-(x-mean)*(x-mean)/sigma/sigma/2.0);
		return term1*term2;
	}

	public static Double logistic3P(Double theta, Double a, Double b, Double c){
		double part1 = java.lang.Math.exp(-a*(theta-b));
		double part2 = 1./(1.+part1);
		return c+(1.-c)*part2;
	}

	public static Double logistic2P(Double theta, Double a, Double b){
		return logistic3P(theta, a, b, 0.);
	}
	
	public static Double logistic1P(Double theta, Double b){
		return logistic3P(theta, 1., b, 0.);
	}

	public static Double GRM(Integer answer, Double theta, Double a, List<Double> b){
		//b contains m-1 values
		//b must be sorted!!!
		Double plow;
		Double phigh;
		if(answer!=0) plow=logistic2P(theta, a, b.get(answer-1));
		else plow = 1.0;
		if(answer!=b.size()) phigh=logistic2P(theta, a, b.get(answer));
		else phigh= 0.0;
		return plow-phigh;
	}
	
	public static Double GRMPrm(Integer answer, Double theta, Double a, List<Double> b){
		//b contains m-1 values
		//b must be sorted!!!
		Double plow;
		Double phigh;
		Double plowPrm;
		Double phighPrm;
		
		if(answer!=0) plow=logistic2P(theta, a, b.get(answer-1));
		else plow = 1.0;
		if(answer!=b.size()) phigh=logistic2P(theta, a, b.get(answer));
		else phigh= 0.0;
		plowPrm=a*plow*(1.-plow);
		phighPrm=a*phigh*(1.-phigh);
		
		return plowPrm-phighPrm;
	}

	public static Double GRMDblPrm(Integer answer, Double theta, Double a, List<Double> b){
		//b contains m-1 values
		//b must be sorted!!!

		Double plow;
		Double phigh;
		Double plowPrm;
		Double phighPrm;
		Double plowDblPrm;
		Double phighDblPrm;
		
		if(answer!=0) plow=logistic2P(theta, a, b.get(answer-1));
		else plow = 1.0;
		if(answer!=b.size()) phigh=logistic2P(theta, a, b.get(answer));
		else phigh= 0.0;
		plowPrm=a*plow*(1.-plow);
		phighPrm=a*phigh*(1.-phigh);
		plowDblPrm = a*plowPrm*(1.-2.*plow);
		phighDblPrm = a*phighPrm*(1.-2.*phigh);
		
		return plowDblPrm-phighDblPrm;
	}	
			
	public static double FisherInfo3PL(Double theta, Double a, Double b, Double c){
		double part1 = java.lang.Math.exp(-a*(theta-b));
		double num = (1.-c)*a*a*part1;
		double den = (1.+part1)*(1.+part1)*(1.+c*part1);
		return num/den;		
	}

	public static double FisherInfoGRM(Double theta, Double a, List<Double> b){
		Double result=0.0;
		Double P;
		Double Pprime;
		for(int i=0; i<b.size(); i++){
			P=GRM(i, theta, a, b);
			Pprime = a*P*(1-P);
			result+=Pprime*Pprime/P;
		}
		return result;
	}
}
